{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Computer Algebra System\n",
    "\n",
    "A computer algebra system (CAS) has the ability to manipulate mathematical\n",
    "expressions in a way similar to the traditional manual computations of\n",
    "mathematicians and scientists.\n",
    "\n",
    "The symbolic manipulations supported include:\n",
    "\n",
    "- simplification to a smaller expression or some standard form,\n",
    "  including automatic simplification with assumptions and\n",
    "  simplification with constraints\n",
    "- substitution of symbols or numeric values for certain expressions\n",
    "- change of form of expressions: expanding products and powers, partial\n",
    "  and full factorization, rewriting as partial fractions, constraint\n",
    "  satisfaction, rewriting trigonometric functions as exponentials,\n",
    "  transforming logic expressions, etc.\n",
    "- partial and total differentiation\n",
    "- matrix operations including products, inverses, etc."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import $ivy.`com.github.haifengl::smile-scala:4.0.0`\n",
    "\n",
    "import smile.cas._"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The CAS module is self-contained. There is no need to import other Smile modules. In the below, we first define a variable `x`. Then we define an expression `e`, which is a function of `x`. For demo purpose, we include some redundant elements, which will be simplified away automatically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val x = Var(\"x\")\n",
    "\n",
    "val e = 0 * x**2 + 1 * x**1 + 1 * x**2 * cot(x**3)\n",
    "println(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also derive the derivative of `e` with respect to `x`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val d = e.d(x)\n",
    "println(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To evaluate an expression, simply apply it on a map of values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d(\"x\" -> Val(1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In fact, we may substitute the variables with other abstract expression rather than only values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val y = x + 2\n",
    "println(d(\"x\" -> y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An expression may contain multiple variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val y = Var(\"y\")\n",
    "val e = sin(x) + cos(y)\n",
    "println(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "println(e.d(x), e.d(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Beyond scalars, we can define vector variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val x = VectorVar(\"x\")\n",
    "val y = VectorVar(\"y\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the dimension of vector, if not specified, is a constant value `n`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val a = Const(\"a\")\n",
    "val b = Const(\"b\")\n",
    "val e = a * x + b * y\n",
    "println(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above example, we define two constant yet abstract values `a` and `b`. Therefore, they will be treated independently from variables when we derive derivative."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "println(e.d(x), e.d(y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the derivate of vector with respect to a vector is matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val dot = x * y\n",
    "println(dot)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As shown, the dot product (or inner product) is a scalar. The derivate of a scalar with respect to a vector, i.e. the gradient, is a vector."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dot.d(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With operator `*~`, we can derive the outer product."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val outer = (2 *x) *~ (3 * y)\n",
    "println(outer)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala (2.13)",
   "language": "scala",
   "name": "scala213"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
